
<!DOCTYPE HTML>
<html>
<head>
	<meta charset="utf-8">
	<title>乐の博客</title>
	<meta name="author" content="zhidong">

	
	<meta name="description" content="nodejs, vscode Nodejs 环境搭建之vscode 开始学习Nodejs了，在这里记录一些轨迹吧。 工欲善其事，必先利其器。在开始之前，先搭好顺手的工具。
Nodejs的安装网上有很多教程了，这里着重介绍开发工具vscode的安装和配置。 &hellip;">
	

  <!-- http://t.co/dKP3o1e -->
  <meta name="HandheldFriendly" content="True">
  <meta name="MobileOptimized" content="320">
  <meta name="viewport" content="width=device-width, initial-scale=1">

	<link href="/atom.xml" rel="alternate" title="乐の博客" type="application/atom+xml">
	
	<link rel="canonical" href="https://zhidong.rochu.cn/">
	<link href="/favicon.png" rel="shortcut icon">
	<link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
	<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
	<script src="/javascripts/libs/jquery.min.js"></script>
	<!-- <link href='//fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'> -->
	
</head>


<body>
	<div class="container">
		<div class="left-col">
			<div class="intrude-less">
			<header id="header" class="inner"><div class="profilepic">	
	<script src="/javascripts/md5.js"></script>
	<script type="text/javascript">
		document.write("<img src='/images/pingtouge.png' alt='Profile Picture' style='width: 160px;' />");
	</script>
</div>
<h1><a href="/">乐の博客</a></h1>
<p class="subtitle">行而不思则罔，思而不行则怠</p>
<nav id="main-nav"><ul>
	<li><a href="/">Blog</a></li>
	<li><a href="/about">About</a></li>
	<li><a href="/portfolio">Portfolio</a></li>
	<li><a href="/archives">Archive</a></li>
</ul>
</nav>
<nav id="sub-nav">
	<div class="social">
		
		<a class="weibo" href="http://www.weibo.com/agdsdl" title="Weibo">Weibo</a>
		
		
		
		
		
		<a class="github" href="https://github.com/agdsdl" title="GitHub">GitHub</a>
		
		
		
		
		
		
		
		<a class="rss" href="/atom.xml" title="RSS">RSS</a>
		
	</div>
</nav>
<p class="description">知冬的后花园</p>
</header>				
			</div>
		</div>	
		<div class="mid-col">
			
				
			
			<div class="mid-col-container">
				<div id="content" class="inner">
<div itemscope itemtype="http://schema.org/Blog">


    <article class="post" itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
	<div class="meta">
		<div class="date">








  


<time datetime="2016-03-15T12:37:13+08:00" data-updated="true" itemprop="datePublished"></time></div>
		<div class="tags">


	<a class='category' href='/blog/categories/nodejs/'>nodejs</a>, <a class='category' href='/blog/categories/vscode/'>vscode</a>


</div>
		
	</div>
	<h1 class="title" itemprop="name"><a href="/blog/2016/03/15/nodejs-startup-tools/" itemprop="url">Nodejs 环境搭建之vscode</a></h1>
	<div class="entry-content" itemprop="articleBody">
		<p>开始学习Nodejs了，在这里记录一些轨迹吧。</p>

<p>工欲善其事，必先利其器。在开始之前，先搭好顺手的工具。
Nodejs的安装网上有很多教程了，这里着重介绍开发工具vscode的安装和配置。
vscode是挺不错的nodejs编辑工具，支持代码提示、自动完成和debug，并且它本身也是nodejs编写的。
当然如果你发现有更好用的工具，也请告诉我。</p>

<h2>nodejs安装</h2>

<p>安装Nodejs，我是从这里看的：<a href="http://nqdeng.github.io/7-days-nodejs/">七天学会nodejs</a>, 还有<a href="https://nodejs.org/">官网</a>.</p>

<h2>下载和安装</h2>

<p>下载地址：<a href="http://code.visualstudio.com/">http://code.visualstudio.com/</a></p>

<h2>配置命令行</h2>

<p>配置命令行，使其可以用命令行这样启动：（仅限MacOS）</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>vscode .
</span></code></pre></td></tr></table></div></figure>


<h3>MacOS系统：</h3>

<p>在.bash_profile文件中加入下面代码：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="k">function</span> vscode <span class="o">()</span> <span class="o">{</span> <span class="nv">VSCODE_CWD</span><span class="o">=</span><span class="s2">&quot;$PWD&quot;</span> open -n -b <span class="s2">&quot;com.microsoft.VSCode&quot;</span> --args <span class="nv">$*</span><span class="p">;</span> <span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>上面代码中的<code>com.microsoft.VSCode</code>是应用的<code>bundle identifier</code>。查看方法：
1. 在应用上点击右键，选择“显示包内容”。
2. 打开<code>Contents</code>目录中的<code>info.plist</code>
3. 其中<code>CFBundleIdentifier</code>键下面的值就是应用的<code>bundle identifier</code>。
其实这种方式适用于大多数Mac应用，比如你可以参考我的<a href="https://github.com/agdsdl/dotfiles/blob/master/source/52_editors.sh">文件</a></p>

<h3>其他系统：</h3>

<p>请参考<a href="https://code.visualstudio.com/docs/editor/setup">https://code.visualstudio.com/docs/editor/setup</a></p>

<h2>配置代码提示和自动完成</h2>

<h3>（2016.4.5勘误）</h3>

<p>发现有时候vscode不能正确的进行代码提示，到vscode官网一看，代码提示的安装方法更新了，以下是最新内容：</p>

<h3>添加jsconfig.json</h3>

<p>在工程目录下新建一个文件<code>jsconfig.json</code>，填入以下内容：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="o">{</span>
</span><span class='line'>    <span class="s2">&quot;compilerOptions&quot;</span>: <span class="o">{</span>
</span><span class='line'>        <span class="s2">&quot;target&quot;</span>: <span class="s2">&quot;es5&quot;</span>,
</span><span class='line'>        <span class="s2">&quot;module&quot;</span>: <span class="s2">&quot;commonjs&quot;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>这告诉vscode你正在使用ES5的javascript标准写代码，下面一行表示支持使用commonjs导出的模块（来进行代码提示）。</p>

<h3>添加TypeScript定义文件</h3>

<p>vscode使用TypeScript定义文件（比如<code>node.d.ts</code>）来提供代码提示和自动完成功能。
vscode推荐使用typings安装和管理TypeScript文件。
首先使用下面代码安装typings：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>npm install -g typings
</span></code></pre></td></tr></table></div></figure>


<p>这将在全局安装typings。</p>

<p>然后，在你的工程目录下，安装你需要的TypeScript文件：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>typings install node --ambient
</span><span class='line'>typings install express serve-static express-serve-static-core --ambient
</span></code></pre></td></tr></table></div></figure>


<p>安装完之后，应该就可以看到代码提示了。</p>

<h3>验证代码提示功能</h3>

<p>有一个简单的方法验证vscode代码提示功能是否正常了：
新起一行输入</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>__dirname
</span></code></pre></td></tr></table></div></figure>


<p>鼠标移到<code>__dirname</code>上，如果提示类型是<code>Any</code>，说明代码提示功能还不正常。
如果能提示类型是<code>string</code>，那么说明代码提示工作正常了。</p>

<p>注：<code>__dirname</code>是nodejs内置全局变量。</p>


		
		<a href="/blog/2016/03/15/nodejs-startup-tools/" class="more-link">Read on &rarr;</a>
	</div>

</article>


    <article class="post" itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
	<div class="meta">
		<div class="date">








  


<time datetime="2016-03-07T20:44:20+08:00" data-updated="true" itemprop="datePublished"></time></div>
		<div class="tags">


	<a class='category' href='/blog/categories/ios/'>ios</a>, <a class='category' href='/blog/categories/kvo/'>kvo</a>, <a class='category' href='/blog/categories/runtime/'>runtime</a>


</div>
		
	</div>
	<h1 class="title" itemprop="name"><a href="/blog/2016/03/07/class-swizzling/" itemprop="url">Class-swizzling, Isa-swizzling and KVO</a></h1>
	<div class="entry-content" itemprop="articleBody">
		<h2>前言</h2>

<p>看<code>ReactiveCocoa</code>源码的时候，被<code>RACSwizzleClass</code>卡住了，做了以下研究，并把注释后的代码放在文章最后，如果不想看过程可以直接跳到最后。</p>

<p><code>RACSwizzleClass</code>中通过判断<code>[obj class]</code>和 <code>object_getClass(obj)</code>是否相同来执行不同的逻辑。
然而<code>[obj class]</code>和<code>object_getClass(obj)</code>有什么区别？他们不同到底意味着什么？</p>

<h2>class和object_getClass</h2>

<p>为此查阅了objc runtime的源代码，并整理了相关代码：<a href="https://gist.github.com/agdsdl/a22666c8f64fed0dbbf5">get class 相关代码</a></p>

<p>结论:</p>

<ul>
<li>对于一个普通的obj（不是class），<code>[obj class]</code>和 <code>object_getClass(obj)</code>会返回一样的结果，就是该对象所属的类。</li>
<li>对于一个class，<code>[aclass class]</code>还是会返回该class，而<code>object_getClass(aclass)</code>会溯本归源返回aclass的<code>isa</code>，一般是返回该类的<code>meta class</code></li>
</ul>


<p>对象的<code>isa</code>链会一直指向哪里?见下图:</p>

<p><img src="/images/class-diagram.jpg" alt="objc 关系图" /></p>

<p>(图片来自<a href="http://blog.devtang.com/2013/10/15/objective-c-object-model/">http://blog.devtang.com/2013/10/15/objective-c-object-model/</a>)</p>

<p>图中的<code>Root class</code>一般是<code>NSObject</code>，当你不停的调用<code>object_getClass</code>，你最终会获取到<code>NSObject</code>的<code>meta class</code>。</p>

<h2>isa-swizzling</h2>

<p>既然对于一个普通的obj（不是class），<code>[obj class]</code>和 <code>object_getClass(obj)</code>会返回一样的结果，那么<code>RACSwizzleClass</code>为什么要做相等性判断？</p>

<p>在苹果的文档中稍稍提到了一些：
<a href="https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOImplementation.html">Key-Value Observing Implementation Details</a></p>

<p>简单的说：</p>

<ul>
<li>系统的KVO，是用<code>isa-swizzling</code>实现的。</li>
<li><code>isa</code>指针，指向对象所属的类，类里面存储的是方法列表及其他一些信息。</li>
<li>当你给一个对象添加了observer之后，系统会修改该对象的<code>isa</code>指针，使其指向一个中间类（中间类重写了setting方法以实现KVO），这时的<code>isa</code>，就不是指向对象实际的类了。</li>
</ul>


<p>所以，你应该用<code>class</code>方法(因为系统同时重写了class方法使其返回对象原来的类)，而不是<code>isa</code>(object_getClass)来取得对象所属的类。</p>


		
		<a href="/blog/2016/03/07/class-swizzling/" class="more-link">Read on &rarr;</a>
	</div>

</article>


    <article class="post" itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
	<div class="meta">
		<div class="date">








  


<time datetime="2016-03-04T14:55:42+08:00" data-updated="true" itemprop="datePublished"></time></div>
		<div class="tags">


	<a class='category' href='/blog/categories/ios/'>ios</a>, <a class='category' href='/blog/categories/runtime/'>runtime</a>


</div>
		
	</div>
	<h1 class="title" itemprop="name"><a href="/blog/2016/03/04/objc-runtime-pickup/" itemprop="url">Objective-c Runtime 拾遗</a></h1>
	<div class="entry-content" itemprop="articleBody">
		<p>关于OC runtime、消息转发网上已经有很多文章，这里就不重复了，只是将一下不常见的、容易遗漏的列一下。</p>

<h2>动态添加类</h2>

<p>我们通过<code>objc_allocateClassPair</code>、<code>class_addIvar</code>、<code>class_addMethod</code>、<code>objc_registerClassPair</code>来动态添加类。</p>

<p><code>objc_registerClassPair</code> 其中除了设置类状态，做的最重要的事是生成<code>ivar_layout</code>(在支持GC的情况下，所以ios中是没有这一步的)，<code>ivar_layout</code>保存了类strong变量的内存视图，runtime依赖他来管理strong变量。</p>

<p><code>ivar_layout</code>的结构<a href="!http://blog.sunnyxx.com/2015/09/13/class-ivar-layout/">阳神的博客里</a>有描述，这里就不重复了。</p>

<p><code>objc_registerClassPair</code>之后，类的<code>instanceSize</code>已经确定，这个新类已经可以投入使用，这时就不允许调用<code>class_addIvar</code>了。</p>

<p><code>class_addIvar</code>主要是对<code>ivar_list</code>链表的操作，并相应的增加<code>instanceSize</code>。</p>

<p>参考：
<a href="http://www.opensource.apple.com/tarballs/objc4/">Apple 源码</a></p>

<h2>动态方法解析</h2>

<p>一个OC方法的实现本质上就是一个简单的c函数，这个c函数至少要有self和_cmd两个参数。比如下面这个c函数：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>void dynamicMethodIMP(id self, SEL _cmd) {
</span><span class='line'>    // implementation ....
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<p>可以用<code>class_addMethod</code>来添加到现有的类中：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>@implementation MyClass
</span><span class='line'>+ (BOOL)resolveInstanceMethod:(SEL)aSEL
</span><span class='line'>{
</span><span class='line'>    if (aSEL == @selector(resolveThisMethodDynamically)) {
</span><span class='line'>          class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
</span><span class='line'>          return YES;
</span><span class='line'>    }
</span><span class='line'>    return [super resolveInstanceMethod:aSEL];
</span><span class='line'>}
</span><span class='line'>@end</span></code></pre></td></tr></table></div></figure>


<p><code>resolveInstanceMethod</code>和<code>resolveClassMethod</code>可以用来动态提供一个方法实现。</p>

<p>OC runtime做消息转发（Message Forwarding）时，在调用<code>respondsToSelector:</code>和<code>instancesRespondToSelector:</code>之前，会先调用上面两个方法，让你有机会来动态添加方法实现。</p>

<p>OC支持一种动态属性允许你动态提供它的实现方法。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>@dynamic propertyName;</span></code></pre></td></tr></table></div></figure>


<p><a href="https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtHowMessagingWorks.html">参考</a></p>


		
		<a href="/blog/2016/03/04/objc-runtime-pickup/" class="more-link">Read on &rarr;</a>
	</div>

</article>


    <article class="post" itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
	<div class="meta">
		<div class="date">








  


<time datetime="2016-02-04T15:38:29+08:00" data-updated="true" itemprop="datePublished"></time></div>
		<div class="tags">


	<a class='category' href='/blog/categories/ios/'>ios</a>, <a class='category' href='/blog/categories/jailbreak/'>jailbreak</a>


</div>
		
	</div>
	<h1 class="title" itemprop="name"><a href="/blog/2016/02/04/write-a-tweak/" itemprop="url">编写一个iOS越狱插件(tweak)</a></h1>
	<div class="entry-content" itemprop="articleBody">
		<p>折腾了几天，搞定一个tweak(FPSCounter)，把一些重要步骤记录一下。</p>

<h2>关于这个插件</h2>

<p>这是个帧速计数器(FPSCounter)，方便我们查看应用的帧速，从而做出相应优化。这里不仅可以看自己的应用，也可以看系统中其他应用。</p>

<h3>截图：</h3>

<p><img src="https://github.com/agdsdl/fpscounter/blob/master/images/preview1.jpg?raw=true" alt="preview1" />
<img src="https://github.com/agdsdl/fpscounter/blob/master/images/preview2.jpg?raw=true" alt="preview2" /></p>

<h3>如何安装</h3>

<ul>
<li>在Cydia中搜索<code>FPSCounter</code>.(你的Cydia中必须有BigBoss源)</li>
<li>或者到<a href="https://github.com/agdsdl/fpscounter">source code</a>下载后自行编译安装。</li>
</ul>


<h2>前提条件</h2>

<p>一个越狱的iOS设备。</p>

<p>需要越狱的设备来获取可用的CydiaSubstrate, 同时也需要越狱设备来安装和测试。</p>

<h2>安装和配置Theos</h2>

<p><a href="https://github.com/DHowett/theos.git">Theos</a>大大简化了tweak的编写，建议大家从Theos开始编写tweak。</p>

<p>按照<a href="http://iosre.com/">《iOS应用逆向工程》</a>中所述，将Theos<a href="https://github.com/DHowett/theos.git">下载</a>下来之后，还有一系列的配置。</p>

<p>我将这些配置工作写成了一个<a href="https://github.com/agdsdl/dotfiles/blob/master/init/82_jailbreak_tools.sh">脚本</a>,省去每次都做这些繁琐的配置。</p>

<p>这个脚本默认Theos是下载到“个人目录/jailbreak/Opensource”，如果不想修改脚本，可用使用与脚本相同的目录。</p>

<h2>配置默认路径</h2>

<p>修改.bash_profile文件，将~/jailbreak/Opensource/theos/bin加入到PATH中。</p>

<p>保存之后重新启动一下终端。</p>

<h2>获取iOS系统头文件</h2>

<p>按照<a href="http://iosre.com/">《iOS应用逆向工程》</a>的介绍，正规的获取方式是用dyld_decache从iOS设备中/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armXX将二进制文件提取出来，然后用class-dump去把头文件提取出来。</p>

<p>为了方便起见，这里采用第二种方法，就是直接用<a href="https://github.com/rpetrich/iphoneheaders.git">rpetrich的头文件</a>。</p>

<p>将这些头文件放到Theos的include目录下。</p>

<p>开始编写tweak！</p>


		
		<a href="/blog/2016/02/04/write-a-tweak/" class="more-link">Read on &rarr;</a>
	</div>

</article>


    <article class="post" itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
	<div class="meta">
		<div class="date">








  


<time datetime="2015-07-29T18:25:47+08:00" data-updated="true" itemprop="datePublished"></time></div>
		<div class="tags">


	<a class='category' href='/blog/categories/octopress/'>octopress</a>


</div>
		
	</div>
	<h1 class="title" itemprop="name"><a href="/blog/2015/07/29/da-jian-ji-yu-octopressde-bo-ke/" itemprop="url">搭建基于Octopress的博客</a></h1>
	<div class="entry-content" itemprop="articleBody">
		<h2>2019.11.12更新</h2>

<p>关于系统更新到MacOS 10.14之后ruby环境的调整，以及多说关闭之后评论系统的选择。</p>

<h3>系统更新到10.14之后</h3>

<p><code>gem install</code>工具会出错：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ sudo gem install bundler
</span><span class='line'>Password:
</span><span class='line'>Fetching: bundler-2.0.2.gem (100%)
</span><span class='line'>ERROR:  While executing gem ... (Gem::FilePermissionError)
</span><span class='line'>    You don't have write permissions for the /usr/bin directory.</span></code></pre></td></tr></table></div></figure>


<p>这是因为Apple在OS X El Capitan中全面启用了名为System Integrity Protection (SIP)的系统完整性保护技术。大部分系统文件禁止直接修改。</p>

<p>要退出SIP需要重启到recovery模式下进行（重启按住command+r），这里采取另一个办法：
<code>/usr/bin</code>禁止写入后，一般都用<code>/usr/local/bin</code>目录替代。<code>gem install</code>可以使用 <code>-n install_path</code>指定安装路径：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>sudo gem install xxx -n /usr/local/bin</span></code></pre></td></tr></table></div></figure>


<p>bundle install的时候还会出错:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ bundle install --path vendor/bundle
</span><span class='line'>Fetching gem metadata from https://rubygems.org/..........
</span><span class='line'>Using rake 10.5.0
</span><span class='line'>Fetching RedCloth 4.2.9
</span><span class='line'>Installing RedCloth 4.2.9 with native extensions
</span><span class='line'>Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
</span><span class='line'>  ...
</span><span class='line'>mkmf.rb can't find header files for ruby at
</span><span class='line'>/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/include/ruby.h
</span><span class='line'>
</span><span class='line'>extconf failed, exit code 1</span></code></pre></td></tr></table></div></figure>


<p>因为macos10.14之后xcode11内置了macos10.15的SDK，预装了ruby2.6，没有ruby2.3的目录</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0</span></code></pre></td></tr></table></div></figure>


<p>但是CommandLineTools里面还有macos10.14的SDK：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/include/ruby-2.3.0</span></code></pre></td></tr></table></div></figure>


<p>通过</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>sudo xcode-select --switch /Library/Developer/CommandLineTools</span></code></pre></td></tr></table></div></figure>


<p>来切换SDK路径</p>

<p>用</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>ruby -rrbconfig -e 'puts RbConfig::CONFIG["rubyhdrdir"]'</span></code></pre></td></tr></table></div></figure>


<p>可以看到路径正确。</p>

<p>之后<code>bundle install</code>可以正常安装。</p>

<p>需要切换回xode11的sdk时：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>sudo xcode-select --switch /Applications/Xcode.app</span></code></pre></td></tr></table></div></figure>


<h3>评论系统的选择</h3>

<p>博客之前采用多说作为评论系统，可是多说关闭了，类似的友言、网易云跟帖等国内评论系统也相继停止服务。Disqus在国内一直被墙，需要重新选择一个评论系统。</p>

<p>看了几天，基本瞄中了基于github issue的评论系统，如果blog也host在github上，那么就很相得益彰。它的数据也没那么容易丢失，除非github倒闭。。。</p>

<p>一开始选择了名气较大的gitment，试用用了一下发现目前已不可用了：
由于采用github API操作issue，因此带来了跨站(CORS)问题，而github禁止跨站，无法直接访问。</p>

<p>解决办法是加一个中间代理服务器，给服务器返回头上添加跨站运行标志。
gitment作者本来自己搭了个代理服务器给大家使用，可是现在已经停服了，如果自己搭代理服务器代价还是颇高的。
而作者已经弃坑，两年多没有更新了，无奈弃之。</p>

<p>后来发现了类似的评论系统：<a href="https://github.com/gitalk/gitalk">gitalk</a>，最近一年还在更新，试了下目前可用。
它是怎么解决跨站问题呢？抓包看了下，发现它采用了Heroku提供的API，专门用于转发请求并允许CORS访问：<a href="https://cors-anywhere.herokuapp.com">https://cors-anywhere.herokuapp.com</a></p>

<p>看来允许跨站请求头是个比较常见的问题。
gitalk的接入方式类似gitment：</p>

<ul>
<li>首先要在github中新建一个OAuth Application，记下Client ID和Client Secret</li>
<li>修改_layouts下面的post.html，在最下面添加：</li>
</ul>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>&lt;section id="comment"&gt;
</span><span class='line'>    &lt;h1 class="title"&gt;Comments&lt;/h1&gt;
</span><span class='line'>    &lt;div id="gitalk-container"&gt;&lt;/div&gt;
</span><span class='line'>    &lt;link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css"&gt;
</span><span class='line'>    &lt;script src="https://unpkg.com/gitalk/dist/gitalk.min.js"&gt;&lt;/script&gt;
</span><span class='line'>    &lt;script&gt;
</span><span class='line'>    const gitalk = new Gitalk({
</span><span class='line'>      clientID: 'GitHub Application Client ID',
</span><span class='line'>      clientSecret: 'GitHub Application Client Secret',
</span><span class='line'>      repo: 'GitHub repo',
</span><span class='line'>      owner: 'GitHub repo owner',
</span><span class='line'>      admin: ['GitHub repo owner and collaborators, only these guys can initialize github issues'],
</span><span class='line'>      id: location.pathname,      // Ensure uniqueness and length less than 50
</span><span class='line'>      distractionFreeMode: false  // Facebook-like distraction free mode
</span><span class='line'>    })
</span><span class='line'>    gitalk.render('gitalk-container')
</span><span class='line'>    &lt;/script&gt;
</span><span class='line'>&lt;/section&gt;</span></code></pre></td></tr></table></div></figure>


<p>GitHub repo可以直接填blog所在的repo，方便集中管理。</p>

<p>博客发出之后需要自己先浏览并登录github账号，以初始化<code>issue page</code>，之后就可以正常评论了。</p>


		
		<a href="/blog/2015/07/29/da-jian-ji-yu-octopressde-bo-ke/" class="more-link">Read on &rarr;</a>
	</div>

</article>


    <article class="post" itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
	<div class="meta">
		<div class="date">








  


<time datetime="2015-07-23T17:23:57+08:00" data-updated="true" itemprop="datePublished"></time></div>
		<div class="tags">


	<a class='category' href='/blog/categories/hybrid/'>hybrid</a>, <a class='category' href='/blog/categories/ios/'>ios</a>, <a class='category' href='/blog/categories/web/'>web</a>


</div>
		
	</div>
	<h1 class="title" itemprop="name"><a href="/blog/2015/07/23/ios-hybridkai-fa-yu-ocjiao-hu/" itemprop="url">IOS Hybrid开发 - 与OC交互</a></h1>
	<div class="entry-content" itemprop="articleBody">
		<ul>
<li>原理：</li>
</ul>


<p>OC调用javascript是通过</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[webView stringByEvaluatingJavaScriptFromString:@"document.title"];</span></code></pre></td></tr></table></div></figure>


<p>javascript调用OC一般是通过在页面中发起一个特定的url请求，然后在OC中响应</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType</span></code></pre></td></tr></table></div></figure>


<p>在响应中判断此url，并做相应的动作。</p>

<p>开源库：<a href="https://github.com/marcuswestin/WebViewJavascriptBridge">https://github.com/marcuswestin/WebViewJavascriptBridge</a></p>


		
		<a href="/blog/2015/07/23/ios-hybridkai-fa-yu-ocjiao-hu/" class="more-link">Read on &rarr;</a>
	</div>

</article>


    <article class="post" itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
	<div class="meta">
		<div class="date">








  


<time datetime="2015-07-23T17:21:17+08:00" data-updated="true" itemprop="datePublished"></time></div>
		<div class="tags">


	<a class='category' href='/blog/categories/hybrid/'>hybrid</a>, <a class='category' href='/blog/categories/ios/'>ios</a>, <a class='category' href='/blog/categories/web/'>web</a>


</div>
		
	</div>
	<h1 class="title" itemprop="name"><a href="/blog/2015/07/23/ios-hybridkai-fa-webji-chu/" itemprop="url">IOS Hybrid开发 - Web基础</a></h1>
	<div class="entry-content" itemprop="articleBody">
		<p>Hybrid开发就是native和web混合开发。他有两方面的优势：跨平台和更新快。
他同时涉及到web开发和native开发。
这里简单讲讲web开发。</p>

<ul>
<li>Web常用目录结构:</li>
</ul>


<p>[name].html 页面文件</p>

<p>style.css 主样式文件</p>

<p>m-style.css 移动平台主样式文件</p>

<p>img/ 图片目录</p>

<p>js/ javascript文件目录</p>

<p>css/ css文件目录</p>


		
		<a href="/blog/2015/07/23/ios-hybridkai-fa-webji-chu/" class="more-link">Read on &rarr;</a>
	</div>

</article>

</div>
<nav id="pagenavi">
    
    
    <div class="center"><a href="/blog/archives">Blog Archives</a></div>
</nav></div>
			</div>
			<footer id="footer" class="inner">Copyright &copy; 2019

    zhidong

<br>
Powered by Octopress.

Design credit: <a href="http://shashankmehta.in/archive/2012/greyshade.html">Shashank Mehta</a></footer>
			<script src="/javascripts/slash.js"></script>
<!-- <script src="/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
	$('.fancybox').fancybox();
})(jQuery);
</script> Delete or comment this line to disable Fancybox -->




	<script type="text/javascript">
		var _gaq = _gaq || [];
		_gaq.push(['_setAccount', 'UA-65560025-1']);
		_gaq.push(['_trackPageview']);

		(function() {
			var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
			ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
			var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
		})();
	</script>



		</div>
	</div>
</body>
</html>
